using AnimCollections;
using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;

namespace DA.AnimGraph {
    public unsafe struct Blackboard : IDisposable {
        private UnsafeHashMap<AUID, ulong> addressMap;
        private ulong baseAddress;
        public bool IsValid => addressMap.IsCreated;

        public Blackboard(int capacity) {
            addressMap = new(capacity, Allocator.Persistent);
            baseAddress = 0;
        }

        public Blackboard(Blackboard other) {
            baseAddress = 0;
            addressMap = default;
            if (!other.IsValid) {
                return;
            }
            AnimNativeUtility.DeepCloneHashMap(out addressMap, other.addressMap, Allocator.Persistent);
        }

        public void Dispose() {
            addressMap.Dispose();
        }

        public void SetBaseAddress<T>(in T memorySlice) where T : unmanaged {
            fixed (T* addr = &memorySlice) {
                baseAddress = (ulong)addr;
            }
        }

        public void SetBaseAddress(ulong inBaseAddress) {
            baseAddress = inBaseAddress;
        }

        public void BindField<T>(AUID uuid, in T field) where T : unmanaged {
            fixed (T* addr = &field) {
                ulong fieldAddress = (ulong)addr;
                fieldAddress -= baseAddress;
                addressMap[uuid] = fieldAddress;
            }
        }

        public void BindFieldByAddress(AUID uuid, ulong addr) {
            ulong fieldAddress = addr;
            fieldAddress -= baseAddress;
            addressMap[uuid] = fieldAddress;
        }

        public bool GetValue<T>(AUID uuid, ref T value) where T : unmanaged {
            if (addressMap.IsCreated && addressMap.TryGetValue(uuid, out var addressOffset)) {
                var addr = baseAddress + addressOffset;
                value = *(T*)addr;
                return true;
            }
            return false;
        }
        public bool SetValue<T>(AUID uuid, T value) where T : unmanaged {
            if (addressMap.IsCreated && addressMap.TryGetValue(uuid, out var addressOffset)) {
                var addr = (T*)(baseAddress + addressOffset);
                *addr = value;
                return true;
            }
            return false;

        }

    }
}
